/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pigx.shop.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.constant.enums.*;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.shop.user.api.dto.ShopCouponDTO;
import com.pig4cloud.pigx.shop.user.api.entity.ShopCoupon;
import com.pig4cloud.pigx.shop.user.api.entity.ShopUserCoupon;
import com.pig4cloud.pigx.shop.user.api.vo.ShopCouponVO;
import com.pig4cloud.pigx.shop.user.api.vo.ShopEquityVO;
import com.pig4cloud.pigx.shop.user.mapper.ShopCouponMapper;
import com.pig4cloud.pigx.shop.user.service.ShopCouponService;
import com.pig4cloud.pigx.shop.user.service.ShopUserCouponService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 商城优惠券
 *
 * @author pigx code generator
 * @date 2023-12-03 12:01:37
 */
@Slf4j
@Service
@AllArgsConstructor
public class ShopCouponServiceImpl extends ServiceImpl<ShopCouponMapper, ShopCoupon> implements ShopCouponService {

	private final ShopUserCouponService shopUserCouponService;

	private final ShopCouponMapper shopCouponMapper;

	/**
	 * 获取领取优惠券列表
	 * @param userId
	 * @return
	 */
	@Override
	public List<ShopCouponVO> getCouponList(Long userId) {
		List<ShopCouponVO> result = new ArrayList<>();

		// 获取所有可用领取的优惠券
		LambdaQueryWrapper<ShopCoupon> lqwCoupon = new LambdaQueryWrapper<>();
		lqwCoupon.eq(ShopCoupon::getStatus, BooleanTypeEnum.TRUE.getType());
		lqwCoupon.eq(ShopCoupon::getCouponCate, CouponCateEnum.USER_RECEIVE.getType());
		lqwCoupon.orderBy(true, true, ShopCoupon::getOrderBy);
		List<ShopCoupon> couponList = list(lqwCoupon);
		// 存在优惠券的场合
		// 判断优惠券是否可以领取
		for (ShopCoupon coupon : couponList) {
			ShopCouponVO vo = new ShopCouponVO();
			BeanUtils.copyProperties(coupon, vo);

			// 获取优惠券状态
			getCouponStatus(vo, null);

			// 过滤已过期的优惠券
			if (vo.getCouponCurrentStatus().equals(CouponCurrentStatusEnum.EXPIRED.getType())) {
				continue;
			}

			if (userId == null) {
				// 未登录的场合，都可以领取
				vo.setHasObtained(BooleanTypeEnum.FALSE.getType());
			}
			else {
				// 用户登录的场合
				// 获取当前用户优惠券
				LambdaQueryWrapper<ShopUserCoupon> lqwShopUserCoupon = new LambdaQueryWrapper<>();
				lqwShopUserCoupon.eq(ShopUserCoupon::getCouponId, coupon.getId());
				lqwShopUserCoupon.eq(ShopUserCoupon::getShopUserId, userId);
				ShopUserCoupon shopUserCoupons = shopUserCouponService.getOne(lqwShopUserCoupon, false);
				if (shopUserCoupons != null) {
					getCouponStatus(vo, shopUserCoupons.getCreateTime());
					// 已经领取
					vo.setHasObtained(BooleanTypeEnum.TRUE.getType());
				}
				else {
					// 未领取
					vo.setHasObtained(BooleanTypeEnum.FALSE.getType());
				}
			}
			result.add(vo);
		}

		if (result.size() > 0) {
			// 按领取顺序排序
			result = result.stream().sorted(Comparator.comparing(ShopCouponVO::getHasObtained))
					.collect(Collectors.toList());
		}

		return result;
	}

	/**
	 * 获取可用的优惠券
	 * @return
	 */
	@Override
	public List<ShopCouponVO> getAvailableCoupon(Long shopUserId) {
		return getUserCouponList(shopUserId, true);
	}

	/**
	 * 获取我的优惠券
	 * @param shopUserId
	 * @return
	 */
	@Override
	public List<ShopCouponVO> getMyCoupon(Long shopUserId) {
		return getUserCouponList(shopUserId, false);
	}

	private List<ShopCouponVO> getUserCouponList(Long shopUserId, boolean isUsed) {
		List<ShopCouponVO> result = new ArrayList<>();
		LambdaQueryWrapper<ShopUserCoupon> lqwShopUserCoupon = new LambdaQueryWrapper<>();
		lqwShopUserCoupon.eq(ShopUserCoupon::getShopUserId, shopUserId);
		if (isUsed) {
			// 状态是未使用的
			lqwShopUserCoupon.eq(ShopUserCoupon::getUseStatus, CouponUseStatusEnum.NOT_USED.getType());
		}
		lqwShopUserCoupon.orderByDesc(ShopUserCoupon::getCreateTime);
		List<ShopUserCoupon> shopUserCoupons = shopUserCouponService.list(lqwShopUserCoupon);
		if (shopUserCoupons.size() <= 0) {
			// 不存在优惠券的场合
			return result;
		}
		List<Long> couponIds = new ArrayList<>();
		shopUserCoupons.forEach(item -> {
			couponIds.add(item.getCouponId());
		});

		// 去重
		List<Long> distinctList = couponIds.stream().distinct().collect(Collectors.toList());

		// 获取对应的优惠券
		LambdaQueryWrapper<ShopCoupon> lqwShopCoupon = new LambdaQueryWrapper<>();
		lqwShopCoupon.in(ShopCoupon::getId, distinctList);
		List<ShopCoupon> shopCoupons = this.list(lqwShopCoupon);
		// List<ShopCoupon> shopCoupons = shopCouponMapper.getShopCouponList(couponIds);

		for (ShopUserCoupon userCoupon : shopUserCoupons) {
			ShopCouponVO vo = new ShopCouponVO();
			Optional<ShopCoupon> shopCoupon = shopCoupons.stream()
					.filter(p -> p.getId().longValue() == userCoupon.getCouponId().longValue()).findFirst();
			if (shopCoupon.isPresent()) {
				// 存在当前优惠券的场合
				ShopCoupon coupon = shopCoupon.get();
				BeanUtils.copyProperties(coupon, vo);
				// 设置用户领取的记录id
				vo.setShopUserCouponId(userCoupon.getId());
				if (userCoupon.getUseStatus().equals(CouponUseStatusEnum.USED.getType())) {
					// 已使用的场合
					vo.setCouponCurrentStatus(CouponCurrentStatusEnum.USED.getType());
				}
				else if (userCoupon.getUseStatus().equals(CouponUseStatusEnum.CANCEL.getType())) {
					// 已作废的场合
					vo.setCouponCurrentStatus(CouponCurrentStatusEnum.INVALID.getType());
				}
				else {
					// 未使用的场合
					// 获取优惠券可用状态
					getCouponStatus(vo, userCoupon.getCreateTime());
				}

				result.add(vo);
			}
		}
		return result;
	}

	/**
	 * 分页获取用户可用的优惠券
	 * @param page
	 * @param shopCouponDTO
	 * @return
	 */
	@Override
	public IPage<ShopCouponVO> getAvailableCouponPage(Page page, ShopCouponDTO shopCouponDTO) {
		IPage<ShopCouponVO> result = new Page<>();
		result.setRecords(new ArrayList<>());
		LambdaQueryWrapper<ShopUserCoupon> lqwShopUserCoupon = new LambdaQueryWrapper<>();
		lqwShopUserCoupon.eq(ShopUserCoupon::getShopUserId, shopCouponDTO.getShopUserId());
		// 状态是未使用的
		lqwShopUserCoupon.eq(ShopUserCoupon::getUseStatus, CouponUseStatusEnum.NOT_USED.getType());
		lqwShopUserCoupon.eq(ShopUserCoupon::getDelFlag, DeleteFlagEnum.VALID.getType());
		IPage<ShopUserCoupon> shopUserCoupons = shopUserCouponService.page(page, lqwShopUserCoupon);
		if (shopUserCoupons.getRecords().size() <= 0) {
			// 不存在优惠券的场合
			return result;
		}
		List<Long> couponIds = new ArrayList<>();
		shopUserCoupons.getRecords().forEach(item -> {
			couponIds.add(item.getCouponId());
		});

		// 去重
		List<Long> distinctList = couponIds.stream().distinct().collect(Collectors.toList());
		// 获取对应的优惠券
		LambdaQueryWrapper<ShopCoupon> lqwShopCoupon = new LambdaQueryWrapper<>();
		lqwShopCoupon.in(ShopCoupon::getId, distinctList);
		List<ShopCoupon> shopCoupons = this.list(lqwShopCoupon);
		// List<ShopCoupon> shopCoupons = shopCouponMapper.getShopCouponList(couponIds);

		for (ShopUserCoupon userCoupon : shopUserCoupons.getRecords()) {
			ShopCouponVO vo = new ShopCouponVO();
			Optional<ShopCoupon> shopCoupon = shopCoupons.stream()
					.filter(p -> p.getId().longValue() == userCoupon.getCouponId().longValue()).findFirst();
			if (shopCoupon.isPresent()) {
				// 存在当前优惠券的场合
				ShopCoupon coupon = shopCoupon.get();
				BeanUtils.copyProperties(coupon, vo);
				// 获取优惠券可用状态
				getCouponStatus(vo, userCoupon.getCreateTime());
				result.getRecords().add(vo);
			}
		}
		return result;
	}

	/**
	 * 用户领取优惠券
	 * @param userId
	 * @return
	 */
	@Override
	public R obtainCouponByUserId(Long userId, Long couponId) {
		// 判断当前优惠券是否可用
		LambdaQueryWrapper<ShopCoupon> lqwShopCoupon = new LambdaQueryWrapper<>();
		lqwShopCoupon.eq(ShopCoupon::getId, couponId);
		lqwShopCoupon.eq(ShopCoupon::getStatus, BooleanTypeEnum.TRUE.getType());
		lqwShopCoupon.eq(ShopCoupon::getDelFlag, DeleteFlagEnum.VALID.getType());
		ShopCoupon coupon = this.getOne(lqwShopCoupon);
		if (coupon == null) {
			return R.failed("不存在当前优惠券，无法领取");
		}

		// 判断当前用户是否已经领取优惠券
		LambdaQueryWrapper<ShopUserCoupon> lqwShopUserCoupon = new LambdaQueryWrapper<>();
		lqwShopUserCoupon.eq(ShopUserCoupon::getCouponId, couponId);
		lqwShopUserCoupon.eq(ShopUserCoupon::getShopUserId, userId);
		ShopUserCoupon shopUserCoupon = shopUserCouponService.getOne(lqwShopUserCoupon, false);
		if (shopUserCoupon != null) {
			return R.failed("用户已领取当前优惠券");
		}

		// 用户领取优惠券
		ShopUserCoupon record = new ShopUserCoupon();
		record.setCouponId(couponId);
		record.setShopUserId(userId);
		record.setUseStatus(CouponUseStatusEnum.NOT_USED.getType());
		shopUserCouponService.save(record);

		return R.ok();
	}

	/**
	 * 判断优惠券是否可用
	 * @return
	 */
	private void getCouponStatus(ShopCouponVO vo, LocalDateTime obtainDateTime) {
		if (vo.getStatus().equals(BooleanTypeEnum.FALSE.getType())) {
			// 下架的场合
			vo.setCouponCurrentStatus(CouponCurrentStatusEnum.INVALID.getType());
		}
		else {
			// 判断优惠券是否在有效期内
			if (vo.getExpirationType().equals(CouponExpirationTypeEnum.FIXTURE_TIME.getType())) {
				// 当前时间
				LocalDateTime currentTime = LocalDateTime.now();
				// 当前时间大于了优惠券结束时间, 不显示当前优惠券
				if (currentTime.isAfter(vo.getEffectiveEndDate())) {
					// 优惠券已过期
					vo.setCouponCurrentStatus(CouponCurrentStatusEnum.EXPIRED.getType());
				}
				else if (currentTime.isBefore(vo.getEffectiveStartDate())) {
					// 优惠券未开始
					vo.setCouponCurrentStatus(CouponCurrentStatusEnum.NOT_STARTED.getType());
				}
				else {
					// 优惠券进行中
					vo.setCouponCurrentStatus(CouponCurrentStatusEnum.IN_PROGRESS.getType());
				}
			}
			else if (vo.getExpirationType().equals(CouponExpirationTypeEnum.GET_AVAILABLE.getType())) {
				// 领券后生效的场合
				// 存在领取时间的场合
				if (obtainDateTime != null) {
					// 当前时间
					LocalDateTime currentTime = LocalDateTime.now();

					// 判断领取时间是否在当前时间内
					LocalDateTime endDate = obtainDateTime.plusDays(vo.getEffectiveDays());
					if (currentTime.isAfter(endDate)) {
						// 优惠券已过期
						vo.setCouponCurrentStatus(CouponCurrentStatusEnum.EXPIRED.getType());
					}
					else {
						// 在范围内，正常使用
						vo.setCouponCurrentStatus(CouponCurrentStatusEnum.IN_PROGRESS.getType());
					}
				}
				else {
					// 不存在领取时间的场合, 在范围内，正常使用
					vo.setCouponCurrentStatus(CouponCurrentStatusEnum.IN_PROGRESS.getType());
				}
			}
		}
	}

	/**
	 * 判断用户优惠券是否有效
	 * @param userCoupon
	 * @return
	 */
	@Override
	public R checkUserCouponStatue(ShopUserCoupon userCoupon) {

		LambdaQueryWrapper<ShopUserCoupon> lqwShopUserCoupon = new LambdaQueryWrapper<>();
		lqwShopUserCoupon.eq(ShopUserCoupon::getShopUserId, userCoupon.getShopUserId());
		if (userCoupon.getCouponId() != null) {
			lqwShopUserCoupon.eq(ShopUserCoupon::getCouponId, userCoupon.getCouponId());
		}
		else if (userCoupon.getId() != null) {
			lqwShopUserCoupon.eq(ShopUserCoupon::getId, userCoupon.getId());
		}
		lqwShopUserCoupon.eq(ShopUserCoupon::getUseStatus, CouponUseStatusEnum.NOT_USED.getType());
		ShopUserCoupon shopUserCoupon = shopUserCouponService.getOne(lqwShopUserCoupon, false);

		if (shopUserCoupon == null) {
			return R.failed("当前优惠券已使用或者已失效, 无法使用优惠券");
		}

		// 获取优惠券信息
		LambdaQueryWrapper<ShopCoupon> lqwShopCoupon = new LambdaQueryWrapper<>();
		lqwShopCoupon.eq(ShopCoupon::getId, shopUserCoupon.getCouponId());
		lqwShopCoupon.eq(ShopCoupon::getStatus, BooleanTypeEnum.TRUE.getType());
		ShopCoupon shopCoupon = this.getOne(lqwShopCoupon);
		if (shopCoupon == null) {
			return R.failed("当前优惠券已失效，无法使用");
		}

		ShopCouponVO vo = new ShopCouponVO();
		BeanUtils.copyProperties(shopCoupon, vo);
		getCouponStatus(vo, shopUserCoupon.getCreateTime());

		if (vo.getCouponCurrentStatus().equals(CouponCurrentStatusEnum.NOT_STARTED.getType())) {
			return R.failed("当前优惠券无法时候，活动未开始");
		}

		if (vo.getCouponCurrentStatus().equals(CouponCurrentStatusEnum.EXPIRED.getType())) {
			return R.failed("当前优惠券已过期，无法使用");
		}
		return R.ok();
	}

	/**
	 * 使用优惠券
	 * @param shopUserId
	 * @param shopUserCouponId
	 * @param orderId
	 * @return
	 */
	@Override
	public boolean useUserCoupon(Long shopUserId, Long shopUserCouponId, Long orderId) {
		log.info("抵扣订单ID:" + orderId + " 抵扣优惠券ID:" + shopUserCouponId + " 用户ID:" + shopUserId);
		LambdaQueryWrapper<ShopUserCoupon> lqwShopUserCoupon = new LambdaQueryWrapper<>();
		lqwShopUserCoupon.eq(ShopUserCoupon::getShopUserId, shopUserId);
		lqwShopUserCoupon.eq(ShopUserCoupon::getId, shopUserCouponId);
		lqwShopUserCoupon.eq(ShopUserCoupon::getUseStatus, CouponUseStatusEnum.NOT_USED.getType());
		ShopUserCoupon shopUserCoupon = shopUserCouponService.getOne(lqwShopUserCoupon);
		if (shopUserCoupon != null) {
			shopUserCoupon.setUseStatus(CouponUseStatusEnum.USED.getType());
			// shopUserCoupon.setUseStatus(useStatus);
			shopUserCoupon.setOrderId(orderId);
			shopUserCouponService.updateById(shopUserCoupon);
			log.info("成功抵扣订单ID:" + orderId + " 抵扣优惠券ID:" + shopUserCouponId + " 用户ID:" + shopUserId);
		}
		return true;
	}

	/**
	 * 发放优惠券给用户
	 * @param shopCouponVOS
	 * @return
	 */
	@Override
	public R giveCoupon(List<ShopCouponVO> shopCouponVOS) {
		if (shopCouponVOS.size() <= 0) {
			return R.failed("未选择当前发放的优惠券");
		}

		// 判断优惠券是否是赠送类型
		for (ShopCouponVO shopCouponVO : shopCouponVOS) {
			if (!shopCouponVO.getCouponCate().equals(CouponCateEnum.GIVE.getType())) {
				return R.failed("当前优惠券不是发放类型");
			}
		}

		// 判断当前优惠券用户是否领取未使用
		Long shopUserId = shopCouponVOS.get(0).getShopUserId();
		List<Long> couponIds = new ArrayList<>();
		for (ShopCouponVO shopCouponVO : shopCouponVOS) {
			couponIds.add(shopCouponVO.getId());
		}
		LambdaQueryWrapper<ShopUserCoupon> lqwShopUserCoupon = new LambdaQueryWrapper<>();
		lqwShopUserCoupon.eq(ShopUserCoupon::getShopUserId, shopUserId);
		lqwShopUserCoupon.in(ShopUserCoupon::getCouponId, couponIds);
		lqwShopUserCoupon.eq(ShopUserCoupon::getUseStatus, CouponUseStatusEnum.NOT_USED.getType());
		long notUsedCount = shopUserCouponService.count(lqwShopUserCoupon);
		if (notUsedCount > 0) {
			return R.failed("当前用户存在相同未使用的优惠券，无法再次赠送");
		}

		List<ShopUserCoupon> list = new ArrayList<>();
		shopCouponVOS.forEach(item -> {
			ShopUserCoupon shopUserCoupon = new ShopUserCoupon();
			shopUserCoupon.setShopUserId(item.getShopUserId());
			shopUserCoupon.setCouponId(item.getId());
			shopUserCoupon.setUseStatus(CouponUseStatusEnum.NOT_USED.getType());
			list.add(shopUserCoupon);
		});
		return R.ok(shopUserCouponService.saveBatch(list));
	}

	/**
	 * 根据用户领取的优惠券记录id获取优惠券信息
	 * @param shopUserCouponId
	 * @return
	 */
	@Override
	public ShopCoupon getCouponInfoByShopUserCouponId(Long shopUserCouponId) {
		ShopCoupon result = null;
		// 获取用户领取优惠券信息
		ShopUserCoupon shopUserCoupon = shopUserCouponService.getById(shopUserCouponId);
		if (shopUserCoupon != null) {
			result = this.getById(shopUserCoupon.getCouponId());
		}
		return result;
	}

	/**
	 * 判断权益包是否可以退款
	 * @param shopEquityVO
	 * @return
	 */
	@Override
	public R checkCancelEquityCoupons(ShopEquityVO shopEquityVO) {
		// 权益包ID
		Long equityId = shopEquityVO.getId();
		Long equityOrderId = shopEquityVO.getEquityOrderId();

		LambdaQueryWrapper<ShopUserCoupon> lqwShopUserCoupon = new LambdaQueryWrapper<>();
		lqwShopUserCoupon.eq(ShopUserCoupon::getEquityOrderId, equityOrderId);
		lqwShopUserCoupon.eq(ShopUserCoupon::getEquityId, equityId);

		// 获取用户领取优惠券信息
		List<ShopUserCoupon> shopUserCoupons = shopUserCouponService.list(lqwShopUserCoupon);
		if (shopUserCoupons.size() <= 0) {
			// 权益包不存在优惠券的场合
			return R.ok();
		}

		// 判断是否存在使用的优惠券
		boolean isUse = false;
		for (ShopUserCoupon userCoupon : shopUserCoupons) {
			// 存在使用的优惠券
			if (userCoupon.getUseStatus().equals(CouponUseStatusEnum.USED.getType())) {
				isUse = true;
				break;
			}
		}

		if (isUse) {
			// 存在已经使用的优惠券
			return R.failed("当前权益包的优惠券已经使用，无法进行退款操作");
		}
		return R.ok();
	}

	/**
	 * 处理权益包退款，优惠券抵消
	 * @param shopEquityVO
	 * @return
	 */
	@Override
	public R cancelEquityCoupons(ShopEquityVO shopEquityVO) {
		// 权益包ID
		Long equityId = shopEquityVO.getId();

		// 获取用户领取优惠券信息
		List<ShopUserCoupon> shopUserCoupons = shopUserCouponService
				.list(Wrappers.<ShopUserCoupon>lambdaQuery().eq(ShopUserCoupon::getEquityId, equityId));
		if (shopUserCoupons.size() <= 0) {
			// 权益包不存在优惠券的场合
			return R.ok();
		}

		// 修改优惠券状态为已作废
		shopUserCoupons.forEach(userCoupon -> {
			userCoupon.setOrderId(null);
			userCoupon.setUseStatus(CouponUseStatusEnum.CANCEL.getType());
		});

		return R.ok(shopUserCouponService.updateBatchById(shopUserCoupons));
	}

	/**
	 * 退回优惠券
	 * @param shopUserCouponId
	 * @return
	 */
	@Override
	public R returnShopUserCoupon(Long shopUserCouponId) {
		ShopUserCoupon shopUserCoupon = shopUserCouponService.getById(shopUserCouponId);
		if (shopUserCoupon != null) {
			shopUserCoupon.setOrderId(null);
			shopUserCoupon.setUseStatus(CouponUseStatusEnum.NOT_USED.getType());
			shopUserCouponService.updateById(shopUserCoupon);
		}
		return R.ok();
	}

}
